/* * MIT License * * Copyright (c) 2017 Inova IT * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package si.inova.neatle.operation; import android.bluetooth.BluetoothGatt; import android.bluetooth.BluetoothGattCharacteristic; import android.bluetooth.BluetoothGattService; import android.os.Build; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import java.io.IOException; import java.util.UUID; import si.inova.neatle.BuildConfig; import si.inova.neatle.Device; import si.inova.neatle.Neatle; import si.inova.neatle.source.InputSource; import si.inova.neatle.source.StringInputSource; import static junit.framework.Assert.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.refEq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(RobolectricTestRunner.class) @Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.N_MR1) public class WriteCommandTest { private UUID serviceUUID = Neatle.createUUID(1); private UUID characteristicUUID = Neatle.createUUID(2); @Mock private CommandObserver commandObserver; @Mock private CommandObserver operationCommandObserver; @Mock private BluetoothGatt gatt; @Mock private Device device; @Mock private BluetoothGattService gattService; @Mock private BluetoothGattCharacteristic gattCharacteristic; private WriteCommand writeCommand; @Before public void setUp() { MockitoAnnotations.initMocks(this); InputSource inputSource = new StringInputSource("lorem ipsum dolor sit amet"); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); } @Test public void testServiceNotFound() { when(gatt.getService(eq(serviceUUID))).thenReturn(null); writeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(); } @Test public void testCharacteristicNotFound() { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); writeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(); } @Test public void testWriteFirstChunkFailed() throws IOException { InputSource inputSource = Mockito.mock(InputSource.class); doThrow(IOException.class).when(inputSource).open(); when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); WriteCommand writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); CommandResult result = CommandResult.createErrorResult(characteristicUUID, BluetoothGatt.GATT_FAILURE); verify(commandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); Mockito.reset(commandObserver, operationCommandObserver, inputSource); when(inputSource.nextChunk()).thenThrow(IOException.class); writeCommand.execute(device, operationCommandObserver, gatt); verify(commandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); } @Test public void testWriteSuccessEmpty() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.readCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(null); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); CommandResult result = CommandResult.createEmptySuccess(characteristicUUID); verify(commandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); } @Test public void testWriteSuccess() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(new byte[]{21, 22}); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); verify(commandObserver, times(0)).finished(any(Command.class), any(CommandResult.class)); verify(operationCommandObserver, times(0)).finished(any(Command.class), any(CommandResult.class)); reset(commandObserver, operationCommandObserver); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(false); writeCommand.execute(device, operationCommandObserver, gatt); verifyCommandFail(); } @Test public void testOnCharacteristicWriteFail() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(new byte[]{21, 22}); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); writeCommand.onCharacteristicWrite(gatt, gattCharacteristic, BluetoothGatt.GATT_FAILURE); verifyCommandFail(); } @Test public void testOnCharacteristicWriteFai2() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(new byte[]{21, 22}); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); doThrow(IOException.class).when(inputSource).nextChunk(); writeCommand.onCharacteristicWrite(gatt, gattCharacteristic, BluetoothGatt.GATT_SUCCESS); verifyCommandFail(); } @Test public void testOnCharacteristicWriteFinished() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(new byte[]{12, 21}); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); when(inputSource.nextChunk()).thenReturn(null); writeCommand.onCharacteristicWrite(gatt, gattCharacteristic, BluetoothGatt.GATT_SUCCESS); CommandResult result = CommandResult.createEmptySuccess(characteristicUUID); verify(commandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); } @Test public void testOnCharacteristicWriteNextChunk() throws IOException { when(gatt.getService(eq(serviceUUID))).thenReturn(gattService); when(gattService.getCharacteristic(characteristicUUID)).thenReturn(gattCharacteristic); when(gatt.writeCharacteristic(eq(gattCharacteristic))).thenReturn(true); InputSource inputSource = Mockito.mock(InputSource.class); when(inputSource.nextChunk()).thenReturn(new byte[]{12, 21}); writeCommand = new WriteCommand( serviceUUID, characteristicUUID, BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT, inputSource, commandObserver); writeCommand.execute(device, operationCommandObserver, gatt); writeCommand.onCharacteristicWrite(gatt, gattCharacteristic, BluetoothGatt.GATT_SUCCESS); verify(commandObserver, times(0)).finished(any(Command.class), any(CommandResult.class)); verify(operationCommandObserver, times(0)).finished(any(Command.class), any(CommandResult.class)); } @Test public void testOnError() { writeCommand.execute(device, operationCommandObserver, gatt); reset(operationCommandObserver, commandObserver); writeCommand.onError(BluetoothGatt.GATT_FAILURE); verifyCommandFail(); } @Test public void testToStringBecauseWhyNot() { assertNotNull(writeCommand.toString()); } private void verifyCommandFail() { CommandResult result = CommandResult.createErrorResult(characteristicUUID, BluetoothGatt.GATT_FAILURE); verify(commandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); verify(operationCommandObserver, times(1)).finished(eq(writeCommand), refEq(result, "timestamp")); } }